/*
 *  This file contains the code for controlling the HVAC system
 *	To access its public functions, include "HVACControl.h"
 */
#include "HVACControl.h"
#include "hvac.h"
#include "eeprom.h"
#include "Schedule.h"
#include "temperature.h"
#include <stdio.h>
#include "ThreadControl.h"
#include "Types.h"
#include "sleep.h"
#include "TimeDate.h"
#include "ZSysgen.h"
#include "ZTypes.h"
#include "ZThread.h"
#include "ZTimer.h"
#include "History.h"

/* Private function declarations */
error_t initTempControl();
error_t adjustHVAC(TIME_t *pollSeconds);
BOOL allowHeatTurnOn();
BOOL allowACTurnOn();
BOOL allowACFanOff();
error_t readCurTemp(temp_unit_t, temp_t offset);
void updateHeatOffTemp(temp_t);
void updateACOffTemp(temp_t);
void turnFanOn();
void turnFanOff();
void turnHeatOn();
void turnHeatOff();
void turnACOn();
void turnACOff();
void resetStates();
void startFanShutoffTimer();

//Timer Variables
extern TICK_t ticksPerSecond;
void HVACTimerFunction();
RZK_TIMERHANDLE_t HVACTimerHandle;
TICK_t HVACTimerInitialDelay = 0;
TICK_t HVACTimerPeriod;

//Used for shutting off fan after AC
void fanShutoffTimerFunction();
RZK_TIMERHANDLE_t fanShutoffTimerHandle;
TICK_t fanShutoffTimerInitialDelay = 0;
TICK_t fanShutoffTimerPeriod;


// The current room temperature
float curTemp = 0;

// The last time we shut the heater off
TIME_t lastHeatShutoff = 0;

// The last time we shut the AC off
TIME_t lastACShutoff = 0;

// The temperature at which to shutoff the heat or AC to prevent overshoot
// TODO: need to implement some learning for this
temp_t ACOffTemp = DEFAULT_SET_TEMP;
temp_t heatOffTemp = DEFAULT_SET_TEMP;

// The current running state of the HVAC (Idle, Heating, Cooling)
hvac_state_t curHVACState = DEFAULT_HVAC_STATE;

// The current mode of the fan (Auto, On)
fan_state_t curFanState = DEFAULT_FAN_STATE;

BOOL ACShutFanOff = FALSE;

TIME_t oldPollingInterval;
TIME_t pollingInterval;

TIME_t startACTime = 0;
TIME_t startHeatTime = 0;
TIME_t startFanTime = 0;


/*
 * Initialize the temperature control system
 * Should be called on startup
 *
 * Params:
 *		none
 *
 * Returns:
 *		SUCCESS when the system is inialized successfully
 */
 error_t initTempControl()
 {
	// Set all of our relay pins to low (0)
	HEAT_RELAYS_PORT = HEAT_RELAYS_PORT & ~((1 << HEAT_ON_PIN_POS) | (1 << HEAT_OFF_PIN_POS));
	AC_RELAYS_PORT = AC_RELAYS_PORT & ~((1 << AC_ON_PIN_POS) | (1 << AC_OFF_PIN_POS));
	FAN_RELAYS_PORT = FAN_RELAYS_PORT & ~((1 << FAN_ON_PIN_POS) | (1 << FAN_OFF_PIN_POS));

 	//Configure the GPIO Port to be in Output mode for our pins
	HEAT_RELAYS_PORT_DDR = HEAT_RELAYS_PORT_DDR & ~((1 << HEAT_ON_PIN_POS) | (1 << HEAT_OFF_PIN_POS));
	HEAT_RELAYS_PORT_ALT1 = HEAT_RELAYS_PORT_ALT1 & ~((1 << HEAT_ON_PIN_POS) | (1 << HEAT_OFF_PIN_POS));
	HEAT_RELAYS_PORT_ALT2 = HEAT_RELAYS_PORT_ALT2 & ~((1 << HEAT_ON_PIN_POS) | (1 << HEAT_OFF_PIN_POS));

	AC_RELAYS_PORT_DDR = AC_RELAYS_PORT_DDR & ~((1 << AC_ON_PIN_POS) | (1 << AC_OFF_PIN_POS));
	AC_RELAYS_PORT_ALT1 = AC_RELAYS_PORT_ALT1 & ~((1 << AC_ON_PIN_POS) | (1 << AC_OFF_PIN_POS));
	AC_RELAYS_PORT_ALT2 = AC_RELAYS_PORT_ALT2 & ~((1 << AC_ON_PIN_POS) | (1 << AC_OFF_PIN_POS));

	FAN_RELAYS_PORT_DDR = FAN_RELAYS_PORT_DDR & ~((1 << FAN_ON_PIN_POS) | (1 << FAN_OFF_PIN_POS));
	FAN_RELAYS_PORT_ALT1 = FAN_RELAYS_PORT_ALT1 & ~((1 << FAN_ON_PIN_POS) | (1 << FAN_OFF_PIN_POS));
	FAN_RELAYS_PORT_ALT2 = FAN_RELAYS_PORT_ALT2 & ~((1 << FAN_ON_PIN_POS) | (1 << FAN_OFF_PIN_POS));

 	turnHeatOff();
	turnACOff();
	turnFanOff();

	curHVACState = IDLE;
	curFanState = FAN_IDLE;
	ACShutFanOff = FALSE;

	//Start the timer
	pollingInterval = DEFAULT_POLLING_INTERVAL;
	oldPollingInterval = pollingInterval;

	fanShutoffTimerPeriod = FAN_RUN_AFTER_AC * ticksPerSecond;

	HVACTimerPeriod = ticksPerSecond * pollingInterval;
	HVACTimerHandle = RZKCreateTimer(NULL, HVACTimerFunction, HVACTimerInitialDelay, HVACTimerPeriod);	

	return SUCCESS;
 }


/*
 * Start the HVAC Timer
 *
 * Params:
 *		none
 *
 * Returns:
 * 		none
 */
error_t startHVACTimer()
{
	if(RZKEnableTimer(HVACTimerHandle) != RZKERR_SUCCESS)
	{
		printf("Error creating HVAC timer\n");
		return GENERAL_ERROR;
	}
	else
	{
		printf("HVAC timer created successfully!\n");
		return SUCCESS;
	}
}


/*
 * Function to control the HVAC
 *
 * Params:
 *		none
 *
 * Returns:
 * 		none
 */
 void HVACTimerFunction()
 {
 	// Adjust HVAC
	printf("Adjust HVAC at time %u\n", RZKSystemTime());
	adjustHVAC(&pollingInterval);
	if(pollingInterval != oldPollingInterval)
	{
		//Restart timer to new time
		RZKDeleteTimer(HVACTimerHandle);

		HVACTimerHandle = RZKCreateTimer(NULL, HVACTimerFunction, HVACTimerInitialDelay, HVACTimerPeriod);	
		if(RZKEnableTimer(HVACTimerHandle) != RZKERR_SUCCESS)
		{
			printf("Error restarting HVAC timer\n");
		}
		else
		{
			printf("HVAC restarted\n");
		}

		oldPollingInterval = pollingInterval;
	}
 }


/*
 * This method can be called by outside files to adjust the HVAC system
 * It calls private helper functions to adjust accordingly
 *
 * Params:
 *		none
 *
 * Returns:
 * 		SUCCESS after adjusting the system
 *		ERROR_GENERAL for unexpected behavior
 */
 error_t adjustHVAC(TIME_t *pollSeconds)
 {
 	eeprom_settings_t allSettings;
	hvac_settings_t *hvacSettings;
	temp_t schedTemp;

	// TODO: error handling
	eepromGetSettings(&allSettings);
	hvacSettings = &allSettings.hvacSettings;

	// Return the number of seconds to wait before polling again
	*pollSeconds = hvacSettings->pollInterval;

	//This is a temporary solution to setting the shutoff setpoints
	updateHeatOffTemp(hvacSettings->setTemp);
	updateACOffTemp(hvacSettings->setTemp);

 	if(hvacSettings->opMode == SCHEDULE_ACTIVE)
	{
		if(isClockTimeValid() == TRUE)
		{
			schedTemp = getTempFromSchedule(allSettings.schedule);
			if(schedTemp != 0)
			{
				hvacSettings->setTemp = schedTemp;
			}
			else
			{
				// We must be running on an empty schedule!
				resetStates();
				return GENERAL_ERROR;
			}
		}
		else
		{
			return GENERAL_ERROR;
		}
	}

	if(hvacSettings->setFanMode == FAN_ON && curFanState != FAN_RUNNING)
	{
		turnFanOn();
	}

	if(hvacSettings->setHVACMode == OFF)
	{
		if(curHVACState == HEATING)
		{
			// The mode has been changed to OFF since last time
			turnHeatOff();
			if(hvacSettings->myHeaterType == ELECTRIC && hvacSettings->setFanMode == FAN_AUTO && curFanState == FAN_RUNNING)
			{
				turnFanOff();
			}
		}
		else if(curHVACState == COOLING)
		{
			turnACOff();
			if(hvacSettings->setFanMode == FAN_AUTO && curFanState != FAN_IDLE)
			{
				//turnFanOff();
				// Schdule the fan to be turned off next time this function is called
				// This is based off the assumption that the adjustHVAC function will be called
				// About every 30 seconds
				ACShutFanOff = TRUE;
				startFanShutoffTimer();
			}
		}
		else if(hvacSettings->setFanMode == FAN_AUTO && curFanState != FAN_IDLE && ACShutFanOff != TRUE)
		{
			// Fan is running when it shouldn't be
			turnFanOff();
		}
		return SUCCESS;
	}

	// Added 4-27 to turn fan off in special cases
	if(curFanState == FAN_RUNNING && hvacSettings->setFanMode == FAN_AUTO)
	{
		// The fan is running when in auto. Should it be?
		if(hvacSettings->setHVACMode == AC)
		{
			if(curHVACState != COOLING && ACShutFanOff == FALSE)
			{
				//The fan shouldn't be running anymore
				turnFanOff();
			}
		}
		if(hvacSettings->setHVACMode == HEAT)
		{
			if(hvacSettings->myHeaterType == GAS)
			{
				// Fan shouldn't be running
				turnFanOff();
			}
			else if(hvacSettings->myHeaterType == ELECTRIC && curHVACState == IDLE)
			{
				turnFanOff();
			}
		}
	}

	// We are either in Heat or A/C mode and are open to running the HVAC if need be
	if( readCurTemp(hvacSettings->tempUnit, allSettings.tempOffset) != SUCCESS)
	{
		//Problem reading the temperature
		return GENERAL_ERROR;
	}

	if(hvacSettings->setHVACMode == AC)
	{
		if(curHVACState != COOLING)
		{
			// We are not cooling
			// Should we?
			if(curTemp >= hvacSettings->setTemp + hvacSettings->tempVariance)
			{
				// The temperature is high enough we should be turning on
				// Have we had the AC off long enough?
				if(allowACTurnOn() == TRUE)
				{
					// Don't need to turn fan on if we are set to FAN_ON already
					if(hvacSettings->setFanMode == FAN_AUTO)
					{
						turnFanOn();
					}
					turnACOn();
				}
			}
		}
		else
		{
			// We are cooling
			// Should we turn off?
			if(curTemp <= ACOffTemp)
			{
				turnACOff();
				// Only turn the fan off if we are in FAN_AUTO
				if(hvacSettings->setFanMode == FAN_AUTO && curFanState != FAN_IDLE)
				{
					//turnFanOff();
					// Schdule the fan to be turned off next time this function is called
					// This is based off the assumption that the adjustHVAC function will be called
					// About every 30 seconds
					ACShutFanOff = TRUE;
					startFanShutoffTimer();
				}
			}
		}
	}
	else if(hvacSettings->setHVACMode == HEAT)
	{
		if(curHVACState != HEATING)
		{
			// We are not heating right now
			// Should we be?
			if(curTemp <= hvacSettings->setTemp - hvacSettings->tempVariance)
			{
				// The heater should be turned on
				// Has it been off long enough?
				if(allowHeatTurnOn() == TRUE)
				{
					turnHeatOn();
					// The existing models did not wait before turning the fan on
					// although it seems like you would want to wait so you don't blow cold air
					if(hvacSettings->myHeaterType == ELECTRIC && hvacSettings->setFanMode == FAN_AUTO && curFanState != FAN_RUNNING)
					{
						turnFanOn();
					}
				}
			}
		}
		else
		{
			// We are heating
			// Should we be?
			if(curTemp >= heatOffTemp)
			{
				turnHeatOff();
				if(hvacSettings->myHeaterType == ELECTRIC && hvacSettings->setFanMode == FAN_AUTO && curFanState == FAN_RUNNING)
				{
					turnFanOff();
				}
			}
			else
			{
				if(hvacSettings->myHeaterType == ELECTRIC && curFanState != FAN_RUNNING)
				{
					// We must have switched from gas to electric heater type
					// in the middle of a heat cycles.  Make sure we turn that fan on
					turnFanOn();
				}
			}
		}
	}


/* I think these can be removed! */
	// Make sure that we didn't just switch to a different HVAC mode
	if(curHVACState == HEATING && hvacSettings->setHVACMode != HEAT)
	{
		turnHeatOff();
		// I think the check for electric should be removed here
		// Because if we were in fan on mode while heating and then switched
		// to fan auto, it would never get shut off
		// !! Nevermind, I took care of this for when new settings are saved
		if(hvacSettings->myHeaterType == ELECTRIC && hvacSettings->setFanMode == FAN_AUTO && curFanState == FAN_RUNNING)
		{
			turnFanOff();
		}
	}
	if(curHVACState == COOLING && hvacSettings->setHVACMode != AC)
	{
		turnACOff();
		if(hvacSettings->setFanMode == FAN_AUTO && curFanState != FAN_IDLE)
		{
			if(hvacSettings->setFanMode == FAN_AUTO && curFanState != FAN_IDLE)
			{
				// Schdule the fan to be turned off
				ACShutFanOff = TRUE;
				startFanShutoffTimer();
			}
		}
	}

	return SUCCESS;
}


/*
 * Public function to return the current temperature
 *
 * Params:
 *		none
 *
 * Returns:
 * 		The value of the current temperature
 *		in the current set temperature unit 
 */
temp_t getCurTemp()
{
	//TODO: call readCurTemp??
	return (temp_t) curTemp;
}


/*
 * Public function to return the set temperature
 *
 * Params:
 *		none
 *
 * Returns:
 * 		The value of the current temperature
 *		in the current set temperature unit 
 */
temp_t getSetTemp()
{
	temp_t setTemp;
	eeprom_settings_t allSettings;
	hvac_settings_t *hvacSettings;

	// TODO: error handling
	eepromGetSettings(&allSettings);
	hvacSettings = &allSettings.hvacSettings;


 	if(hvacSettings->opMode == SCHEDULE_ACTIVE)
	{
		return getTempFromSchedule(allSettings.schedule);
	}
	else
	{
		return hvacSettings->setTemp;
	} 
}

/*
 * Public function to return the current HVAC state
 *
 * Params:
 *		none
 *
 * Returns:
 * 		The value of the current temperature
 *		in the current set temperature unit 
 */
hvac_state_t getCurHVACState()
{
	return curHVACState;
}


/*
 * Private function to read the temperature sensor
 *
 * Params:
 *		none
 *
 * Returns:
 * 		SUCCESS if the temp sensor is read correctly
 *		GENERAL_ERROR if the sensor can't be read
 */
error_t readCurTemp(temp_unit_t unit, temp_t offset)
{
	float readTemp;
	if(temperatureRead(unit, offset, &readTemp) == SUCCESS)
	{
		curTemp = readTemp;
		return SUCCESS;
	}
curTemp = 75; return SUCCESS;
//	return GENERAL_ERROR;
}



/*
 * Private function to check if the HVAC system has been 
 * turned off long enough to be safely turned on again
 * (used to prevent damage to compressors)
 *
 * Params:
 *		none
 *
 * Returns:
 * 		TRUE if the system is able to be changed
 *		FALSE if not enough time has expired for the system to be changed 
 */
BOOL allowHeatTurnOn()
{
	TIME_t curTime = RZKSystemTime();

	if(curTime - lastHeatShutoff >= HEAT_MIN_OFF_PERIOD)
	{
		return TRUE;
	}
	else
	{
		if(curTime < HEAT_MIN_OFF_PERIOD)
		{
			//The board hasn't even been on longer than HEAT_MIN_OFF_PERIOD
			//so it must have just started up.  Allow it to turn on
			return TRUE;
		}
		return FALSE;
	}
}


/*
 * Private function to check if the HVAC system has been 
 * turned off long enough to be safely turned on again
 * (used to prevent damage to compressors)
 *
 * Params:
 *		none
 *
 * Returns:
 * 		TRUE if the system is able to be changed
 *		FALSE if not enough time has expired for the system to be changed 
 */
BOOL allowACTurnOn()
{
	TIME_t curTime = RZKSystemTime();

	if(curTime - lastACShutoff >= AC_MIN_OFF_PERIOD)
	{
		return TRUE;
	}
	else
	{
		if(curTime < AC_MIN_OFF_PERIOD)
		{
			//The board hasn't even been on longer than AC_MIN_OFF_PERIOD
			//so it must have just started up.  Allow it to turn on
			return TRUE;
		}
		return FALSE;
	}
}


/*
 * Private function to see whether the fan has run
 * long enough after shutting off the AC
 * (used to prevent damage to the AC unit)
 *
 * Params:
 *		none
 *
 * Returns:
 * 		TRUE if it is time to turn the fan off
 *		FALSE if still needs to run
 */
BOOL allowACFanOff()
{
	TIME_t curTime = RZKSystemTime();

	if(curTime - lastACShutoff >= FAN_RUN_AFTER_AC)
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}


/*
 * Private function to update the temperature at 
 * which the Heater should turn off
 *
 * Params:
 *		none	
 *
 * Returns:
 * 		none
 */
void updateHeatOffTemp(temp_t in)
{
	//TODO: Add logic to learn on overshoots
	heatOffTemp = in;
}



/*
 * Private function to update the temperature at 
 * which the AC should turn off
 *
 * Params:
 *		none	
 *
 * Returns:
 * 		none
 */
void updateACOffTemp(temp_t in)
{
	//TODO: Add logic to learn on overshoots
	ACOffTemp = in;
}


/*
 * Private function to turn the fan on
 *
 * Params:
 *		none	
 *
 * Returns:
 * 		none
 */
void turnFanOn()
{
	ENTER_CRITICAL_REGION();
	// The two lines of code below are for safety but should never be needed
	// Make sure the on switch for the relay is set to 0
	//RELAYS_PORT = RELAYS_PORT & ~(1 << FAN_OFF_PIN_POS);
	//wait(RELAY_WAIT_PERIOD_MS);

	// Flip the Fan On pin to high
	FAN_RELAYS_PORT = FAN_RELAYS_PORT | (PIN_ON << FAN_ON_PIN_POS);
	// Pause so that the relay has time to flip
	sleep(RELAY_WAIT_PERIOD_MS);

	// The relay should have flipped
	// Now flip the Fan On pin back to low
	FAN_RELAYS_PORT = FAN_RELAYS_PORT & ~(1 << FAN_ON_PIN_POS);

	curFanState = FAN_RUNNING;
	EXIT_CRITICAL_REGION();

	startFanTime = RZKSystemTime();
#ifdef _DEBUG
	printf("Turned fan on\n");
#endif
}


/*
 * Private function to turn the fan off
 *
 * Params:
 *		none
 *
 * Returns:
 * 		none
 */
void turnFanOff()
{
	ENTER_CRITICAL_REGION();
	// The two lines of code below are for safety but should never be needed
	// Make sure the on switch for the relay is set to 0
	//RELAYS_PORT = RELAYS_PORT & ~(1 << FAN_ON_PIN_POS);
	//wait(RELAY_WAIT_PERIOD_MS);

	// Flip the Fan Off pin to high
	FAN_RELAYS_PORT = FAN_RELAYS_PORT | (PIN_ON << FAN_OFF_PIN_POS);
	// Pause so that the relay has time to flip
	sleep(RELAY_WAIT_PERIOD_MS);

	// The relay should have flipped
	// Now flip the Fan Off pin back to low
	FAN_RELAYS_PORT = FAN_RELAYS_PORT & ~(1 << FAN_OFF_PIN_POS);

	curFanState = FAN_IDLE;
	EXIT_CRITICAL_REGION();

	if(startFanTime != 0)
	{
		logFanTime(RZKSystemTime() - startFanTime);
	}
#ifdef _DEBUG
	printf("Turned fan off\n");
#endif
}


/*
 * Private function to turn the heater on
 *
 * Params:
 *		none	
 *
 * Returns:
 * 		none
 */
void turnHeatOn()
{
	ENTER_CRITICAL_REGION();
// The two lines of code below are for safety but should never be needed
	// Make sure the on switch for the relay is set to 0
	//RELAYS_PORT = RELAYS_PORT & ~(1 << HEAT_OFF_PIN_POS);
	//wait(RELAY_WAIT_PERIOD_MS);

	// Flip the Heat On pin to high
	HEAT_RELAYS_PORT = HEAT_RELAYS_PORT | (PIN_ON << HEAT_ON_PIN_POS);
	// Pause so that the relay has time to flip
	sleep(RELAY_WAIT_PERIOD_MS);

	// The relay should have flipped
	// Now flip the Heat On pin back to low
	HEAT_RELAYS_PORT = HEAT_RELAYS_PORT & ~(1 << HEAT_ON_PIN_POS);

	curHVACState = HEATING;
	EXIT_CRITICAL_REGION();

	startHeatTime = RZKSystemTime();
#ifdef _DEBUG
	printf("Turned heat on\n");
#endif
}


/*
 * Private function to turn the heater off
 *
 * Params:
 *		none
 *
 * Returns:
 * 		none
 */
void turnHeatOff()
{
	ENTER_CRITICAL_REGION();
	// The two lines of code below are for safety but should never be needed
	// Make sure the on switch for the relay is set to 0
	//RELAYS_PORT = RELAYS_PORT & ~(1 << HEAT_ON_PIN_POS);
	//wait(RELAY_WAIT_PERIOD_MS);

	// Flip the Heat Off pin to high
	HEAT_RELAYS_PORT = HEAT_RELAYS_PORT | (PIN_ON << HEAT_OFF_PIN_POS);
	// Pause so that the relay has time to flip
	sleep(RELAY_WAIT_PERIOD_MS);

	// The relay should have flipped
	// Now flip the Heat Off pin back to low
	HEAT_RELAYS_PORT = HEAT_RELAYS_PORT & ~(1 << HEAT_OFF_PIN_POS);

	curHVACState = IDLE;
	lastHeatShutoff = RZKSystemTime();
	EXIT_CRITICAL_REGION();

	if(startHeatTime != 0)
	{
		logHeatTime(RZKSystemTime() - startHeatTime);
	}
#ifdef _DEBUG
	printf("Turned heat off\n");
#endif
}


/*
 * Private function to turn the AC on
 *
 * Params:
 *		none
 *		
 * Returns:
 * 		none
 */
void turnACOn()
{
	ENTER_CRITICAL_REGION();
	// The two lines of code below are for safety but should never be needed
	// Make sure the on switch for the relay is set to 0
	//RELAYS_PORT = RELAYS_PORT & ~(1 << AC_OFF_PIN_POS);
	//wait(RELAY_WAIT_PERIOD_MS);

	// Flip the AC On pin to high
	AC_RELAYS_PORT = AC_RELAYS_PORT | (PIN_ON << AC_ON_PIN_POS);
	// Pause so that the relay has time to flip
	sleep(RELAY_WAIT_PERIOD_MS);

	// The relay should have flipped
	// Now flip the AC On pin back to low
	AC_RELAYS_PORT = AC_RELAYS_PORT & ~(1 << AC_ON_PIN_POS);

	curHVACState = COOLING;
	EXIT_CRITICAL_REGION();

	startACTime = RZKSystemTime();
#ifdef _DEBUG
	printf("Turned AC on\n");
#endif
}


/*
 * Private function to turn the AC off
 *
 * Params:
 *		none		
 *
 * Returns:
 * 		none
 */
void turnACOff()
{
	ENTER_CRITICAL_REGION();
	// The two lines of code below are for safety but should never be needed
	// Make sure the on switch for the relays is set to 0
	//RELAYS_PORT = RELAYS_PORT & ~(1 << AC_ON_PIN_POS);
	//wait(RELAY_WAIT_PERIOD_MS);

	// Flip the AC Off pin to high
	AC_RELAYS_PORT = AC_RELAYS_PORT | (PIN_ON << AC_OFF_PIN_POS);
	// Pause so that the relay has time to flip
	sleep(RELAY_WAIT_PERIOD_MS);

	// The relay should have flipped
	// Now flip the AC Off pin back to low
	AC_RELAYS_PORT = AC_RELAYS_PORT & ~(1 << AC_OFF_PIN_POS);

	curHVACState = IDLE;
	lastACShutoff = RZKSystemTime();
	EXIT_CRITICAL_REGION();

	if(startACTime != 0)
	{
		logACTime(RZKSystemTime() - startACTime);
	}
#ifdef _DEBUG
	printf("Turned AC off\n");
#endif
}


/*
 * Private function to reset the states of 
 * the hvac variables to their original states.
 * 
 * This should be called when new settings are saved
 *
 * Params:
 *		none		
 *
 * Returns:
 * 		none
 */
 void startFanShutoffTimer()
 {
	if(fanShutoffTimerHandle == NULL)
	{
		//This must be our first time calling this function
		fanShutoffTimerHandle = RZKCreateTimer(NULL, fanShutoffTimerFunction, fanShutoffTimerInitialDelay, fanShutoffTimerPeriod);	

		if(RZKEnableTimer(fanShutoffTimerHandle) != RZKERR_SUCCESS)
		{
			//Problem - do what???
		}
	}
	else
	{
		RZKEnableTimer(fanShutoffTimerHandle);
	}
 }


/*
 * Private function to reset the states of 
 * the hvac variables to their original states.
 * 
 * This should be called when new settings are saved
 *
 * Params:
 *		none		
 *
 * Returns:
 * 		none
 */
 void fanShutoffTimerFunction()
 {
 	eeprom_settings_t settings;
	eepromGetSettings(&settings);
	//We don't shut the fan off if we are cooling or heating with and electric heater
 	if(curHVACState == IDLE || (curHVACState == HEATING && settings.hvacSettings.myHeaterType == GAS))
	{
		turnFanOff();
	}
	RZKDisableTimer(fanShutoffTimerHandle);
	ACShutFanOff = FALSE;
 }


/*
 * Private function to reset the states of 
 * the hvac variables to their original states.
 * 
 * This should be called when new settings are saved
 *
 * Params:
 *		none		
 *
 * Returns:
 * 		none
 */
void resetStates()
{
	if(curHVACState == HEATING)
	{
		turnHeatOff();
	}
	if(curHVACState == COOLING)
	{
		turnACOff();
		ACShutFanOff = TRUE;
	}
	else
	{
		ACShutFanOff = FALSE;
	}

	curHVACState = IDLE;
	curFanState = FAN_IDLE;
}